/**
 * A symbol table contains variables, condition IDs and event IDs.  
 * Each entry for a variable contains its value, which can be obtained by
 * <code> getValue() </code>.
 * Each entry for a condition ID or an event ID in the symbol table 
 * contains a pointer to the root node of the definition of ID.  
 * That pointer can be obtained by * <code> getPtr() </code>.
 *
 * Each node of type ASTEvent has its value which can be obtained by <code>
 * getValue() </code> 
 */
package mac.eventRecognizer.pedlParser;

import mac.types.parserTypes.*;
import mac.eventRecognizer.interpreter.*;

public class ASTEvent extends SimpleNode {
  static final int START = 0;

  static final int END = 1;
  static final int UPDATE = 2;
  static final int STARTM = 3;
  static final int ENDM = 4;
  static final int IOM = 5;
  static final int AND = 6;
  static final int OR = 7;
  static final int WHEN = 8;
  static final int PARENTHESIS = 9;

  /** This type defines event id in event expression 
   * ex> event end_startIC = endIC || startIC
   *                         ~~~~~    ~~~~~~~
   * Similar difficulty for ASTExpression of type VARIABLE*/
  static final int IDENTIFIER = 10;

  /** This type defines event definition.
   *  ex> event startIC = start(IC) 
   *            ~~~~~~~ */
  static final int ASSIGNMENT = 11;	

  protected int op;
  protected String name;
  protected long time;

  /** This field contains a value related to an event this node represent */ 
  protected Object eventValue;

  /** This method returns the value of an event this node represent */
  public Object getEventValue() { return eventValue;}

  ASTEvent(int id) {
    super(id);
  }

  public int getOp() {
    return op;
  }
  public String getName() {
    return name;
  }
  public long getTime() {
    return time;
  }

  public void setOp(int o) {
    op = o;
  }
  public void setName(String n) {
    name = n;
  }
  public void setTime(long t) {
    time = t;
  }

  /** NOTE.  I don't implement the evaluating the value of the event yet*/
  public Object evaluate() {
      Boolean oldChildValue= null;
      Boolean newChildValue = null; 
      Object newValue = null;// a result of evaluation

      // If this node is already evaluated and not a IDENTIFIER node, 
      // it just returns value.
      // It's because ASTEvent of type IDENTIFIER has its actual value at
      // the definition node, not at the node itself
      if( mark && op != IDENTIFIER ) {
//	  System.err.println(this);
	  return value;	
      }
      mark = true;

      switch(op) {
	  /* A child must be ASTEvent */
	  case ASSIGNMENT  :
	  case PARENTHESIS :	
	  {
	      ASTEvent child = (ASTEvent)jjtGetChild(0);
	      value = child.evaluate();
	      break;
	  }
	      
	  /* A child must be ASTCondition or ASTExpression of type
	   * 	VARIABLE
	   * 	METHOD
	   * 	VALUE
	   * 	ARRAY
	   * 	CAST 
	   */
	   /* Note.  by the definition of START and END, the initial
	   *  evaluateion of this node is false because oldValue is not
	   *  defined.  */
	  case START	   :	
	  {
	      //System.err.println("-----START--------");
	      if( jjtGetChild(0) instanceof ASTCondition) {
		  ASTCondition child = (ASTCondition) jjtGetChild(0);
		  newChildValue = (Boolean)(child.evaluate());
		  oldChildValue = (Boolean)(child.getOldValue());
	      } else {
		  ASTExpression child = (ASTExpression) jjtGetChild(0);
		  newChildValue = (Boolean)(child.evaluate());
		  oldChildValue = (Boolean)(child.getOldValue());
	      }
	      //System.err.println("oldChildValue = " + oldChildValue);
	      //System.err.println("newChildValue = " + newChildValue);

	      if( oldChildValue == null) {	// initial evaluation should false
		  value = new Boolean(false);
	      } else {
		  value = new Boolean( !oldChildValue.booleanValue() 
					&& newChildValue.booleanValue() );
	      }
	      //System.err.println(EventRecognizer.symbolTbl);
	      break;
	  }

	  case END	   :	 
	  {
	      //System.err.println("-----END--------");
	      if( jjtGetChild(0) instanceof ASTCondition) {
		  ASTCondition child = (ASTCondition) jjtGetChild(0);
		  newChildValue = (Boolean)(child.evaluate());
		  oldChildValue = (Boolean)(child.getOldValue());
	      } else {
		  ASTExpression child = (ASTExpression) jjtGetChild(0);
	      //System.err.println("oldChildValue = " + child.getOldValue());
	      //System.err.println("newChildValue = " + 
	      //((Node)((SymtabEntry)(child.getValue())).getValue()).getValue());
	      //System.err.println("......");
	      // NO! DON'T USE child.getValue().  IT's OLD VALUE
	      //System.err.println(child.getValue());// symbol entry
	      //System.err.println("isUpdated? " + 
	      //((SymtabEntry)child.getValue()).isUpdated());
	      //System.err.println( EventRecognizer.symbolTbl.get(child.name));
	      //System.err.println("......");

		  newChildValue = (Boolean)(child.evaluate());
		  oldChildValue = (Boolean)(child.getOldValue());
	      }

	      //System.err.println("oldChildValue = " + oldChildValue);
	      //System.err.println("newChildValue = " + newChildValue);

	      if( oldChildValue == null) { // initial evaluation should false
		  value = new Boolean(false);
	      } else {
		  value = new Boolean( oldChildValue.booleanValue() 
					&& !newChildValue.booleanValue() );
	      }
	      break;
	  }

	  /* A child must be ASTExpression of type VARIABLE.  Especially, a
	   * child must be an exec point*/
	  case STARTM	  :	
	  {
	      ASTExpression child = (ASTExpression)jjtGetChild(0);
	      SymtabEntry se = (SymtabEntry)child.getValue();
	      child.evaluate();		
	      if( !child.isUpdated() ) {// an exec point doesn't arrive 
		  value = new Boolean(false);
	      } else {	// a new exec point arrives
		  if( ((String)(se.getValue())).equals("start")) {
		      value = new Boolean(true);
		  } else {
		      value = new Boolean(false);
		  }
	      }
	      break;
	  }
	  case ENDM	  :	
	  {
	      ASTExpression child = (ASTExpression)jjtGetChild(0);
	      SymtabEntry se = (SymtabEntry)child.getValue();
	      child.evaluate();		
	      if( !child.isUpdated() ) {// an exec point doesn't arrive 
		  value = new Boolean(false);
	      } else {	// a new exec point arrives
		  if( ((String)(se.getValue())).equals("end")) {
		      value = new Boolean(true);
		  } else {
		      value = new Boolean(false);
		  }
	      }
	      break;
	  }
	  case IOM 	  :	
	  {
	      ASTExpression child = (ASTExpression)jjtGetChild(0);
	      SymtabEntry se = (SymtabEntry)child.getValue();
	      child.evaluate();		
	      if( !child.isUpdated() ) {// an exec point doesn't arrive 
		  value = new Boolean(false);
	      } else {	// a new exec point arrives
		  if( ((String)(se.getValue())).equals("start")) {
		      value = new Boolean(true);
		  } else {
		      value = new Boolean(false);
		  }
	      }
	      break;
	  }

	  /* A child must be ASTExpression of type VARIABLE.  Especially, a
	   * child must be a program variable*/
	  case UPDATE 	  :
	  {
	      ASTExpression child = (ASTExpression)jjtGetChild(0);
	      child.evaluate();
	      value = new Boolean( child.isUpdated());
	      break;
	  }

	  /* This node is an event id.  It does not have a child.  Its value
	   * is a pointer to an entry in a symbol table whose key is id of
	   * this node.  Be careful NOT to update value */
	  case IDENTIFIER :
	      SymtabEntry se = (SymtabEntry)value;
	      newValue = ((ASTEvent)(se.getValue())).evaluate(); 
	      break;
	  case OR:
	  {
	      boolean tempResult = false; 
	      for(int i=0; i < jjtGetNumChildren(); i++) {
		  tempResult = tempResult | 
		      ((Boolean)jjtGetChild(i).evaluate()).booleanValue();
	      }
	      value = new Boolean(tempResult);
	      break;
	  }
	  case AND:
	  {
	      boolean tempResult = true ; 
	      for(int i=0; i < jjtGetNumChildren(); i++) {
		  tempResult = tempResult & 
		      ((Boolean)jjtGetChild(i).evaluate()).booleanValue();
	      }
	      value = new Boolean(tempResult);
	      break;
	  }

	  case WHEN:
	      System.err.println("WHEN is not yet implemented");
	      break;
	  default: System.err.println("Incorrect type is detected while "+ this 
			   + " is evaluated!");
      }

      if(op != IDENTIFIER) {
	  newValue = value;
      }
  //    System.err.println("--------------");	    
   //   System.err.println(this);
      //System.err.println(this);
      return newValue;
  }

  public String toString() {
    String s= null;
    String s2= null;
    Object realValue = null;
    SymtabEntry se = null;

    switch (op) {
      case START: s ="Event: start of condition"; break;
      case END: s ="Event: end of condition"; break;
      case UPDATE: s ="Event: update"; break;
      case STARTM: s ="Event: start of method"; break;
      case ENDM: s ="Event: end of method"; break;
      case IOM: s ="Event: input-output of method"; break;
      case AND: s ="Event: and"; break;
      case OR: s ="Event: or"; break;
      case WHEN: s ="Event: when"; break;
      case PARENTHESIS: s ="Event: parenthesis"; break;
      case IDENTIFIER: s ="Event: identifier"; break;
      case ASSIGNMENT: s ="Event: assignment"; break;
      default: s ="Event: error"; break;
    }

      if(value instanceof SymtabEntry) {
	  se = (SymtabEntry)value;
	  if( ((String)(se.getType())).equals("_macType")) {
	      realValue = ((Node)(se.getValue())).getValue(); 
	  } else {
	      realValue = se.getValue();
	  }
      } else {
	  realValue = value;
      }

      return s + "(name:"+ name + ",value:" 
	    + realValue + ",mark:" + mark + ")" ;
  }
}
